#include "PDTAssign.h"
#include "PDTCodeGraph.h"

void
PDTAssign::setTarget(PDTVar &target){
	PDTNode * node =target.getNode();
	addChild(node);
	node->addParent(this);
}

void PDTAssign::setExpression(PDTExp &expression){
	addChild(&expression);
	expression.addParent(this);
}

void PDTAssign::replaceExpression(PDTExp &expression) {
	children[1] = (PDTNode*)(&expression); // replace unresolved expression with new one
	expression.addParent(this);
}

PDTVar * PDTAssign::getTarget()const {
	return dynamic_cast<PDTVar*>(children[0]);
}

PDTExp * PDTAssign::getExpression()const {
	return dynamic_cast<PDTExp*>(children[1]);
}

bool 
PDTAssign::
eval(PDTCodeGraph &CG)
{
    children[1]->eval(CG);
    if (children[0]->isSequenceAccessNum())
    {
        PDTSequenceAccessNum* seqAcc = dynamic_cast<PDTSequenceAccessNum*>(children[0]);
        seqAcc->getRight()->eval(CG);
        PDTNode* indexNode = seqAcc->getRight()->nValue; //Get the index
        int index = (dynamic_cast<PDTNumConstInt*>(indexNode))->getValue();
        int valueToAssign = (dynamic_cast<PDTNumConstInt*>(children[1]->nValue))->getValue(); //Get the value to assign
        seqAcc->getLeft()->elements[index] = new PDTNumConstInt(CG, valueToAssign); //initialize the element
        cout<<"Value ("<<valueToAssign<<") is assigned to: "<<seqAcc->getLeft()->name<<"["<<index<<"]"<<endl;
    }

    else if (children[0]->isSequenceAccessBool())
    {
        PDTSequenceAccessBool* seqAcc = dynamic_cast<PDTSequenceAccessBool*>(children[0]);
        seqAcc->getRight()->eval(CG);
        PDTNode* indexNode = seqAcc->getRight()->nValue;
        int index = (dynamic_cast<PDTBoolConst*>(indexNode))->getValue();
        bool valueToAssign = (dynamic_cast<PDTBoolConst*>(children[1]->nValue))->getValue();
        seqAcc->getLeft()->elements[index] = new PDTBoolConst(CG, valueToAssign);
    }
    else
    {
        if (children[1]->getNValue()->isNumConstInt())
        {
            PDTNumConstInt* child1 = dynamic_cast<PDTNumConstInt*>(children[1]->getNValue());
            int result = child1->getValue(); //get the value to store
            children[0]->nValue = new PDTNumConstInt(CG, result); //store
            cout<<"Value ("<<result<<") is assigned to the variable '"<<getTarget()->getName()<<"'"<<endl;
        }

        else if (children[1]->getNValue()->isBoolConst())
        {
            PDTBoolConst* child1 = dynamic_cast<PDTBoolConst*>(children[1]->getNValue());
            bool result = child1->getValue();
            children[0]->nValue = new PDTBoolConst(CG, result);
            cout<<"Value ("<<result<<") is assigned to the variable '"<<getTarget()->getName()<<"'"<<endl;
        }
        string name = getTarget()->getName();
        int nameSize = name.size();
        if (nameSize>2)
        {
            string varName = name.substr(nameSize-2, nameSize-1);
            if (varName == "rv") //Have a return expression: must stop
            {
                //break
                return false;
            }
        }
    }
    return true;
}

PDTAssign::PDTAssign(PDTCodeGraph & CG, PDTVar &target, PDTExp &expression, bool aIsReturn)
  : PDTStatement(CG), isReturnStatement(aIsReturn)
{
	PDTNode* varNode = target.getNode();
	addChild(varNode);
	varNode->addParent(this);

	addChild(&expression);
	expression.addParent(this);

}

PDTPiAssign::PDTPiAssign(PDTCodeGraph & CG, PDTVar & target) :
    PDTStatement(CG) {
        PDTNode * varNode = target.getNode();
        addChild(varNode);
        varNode->addParent(this);
}

void
PDTPiAssign::setTarget(PDTVar &target){
	PDTNode * node =target.getNode();
	addChild(node);
	node->addParent(this);
}

void 
PDTPiAssign::setExpression(PDTExp &expression){
	addChild(&expression);
	expression.addParent(this);
}

void
PDTPiAssign::replaceExpression(PDTExp &expression) {
	children[1] = (PDTNode*)(&expression); // replace unresolved expression with new one
	expression.addParent(this);
}

PDTVar * 
PDTPiAssign::getTarget()const {
	return dynamic_cast<PDTVar*>(children[0]);
}

PDTExp * 
PDTPiAssign::getExpression()const {
	return dynamic_cast<PDTExp*>(children[1]);
}

PDTSequenceAssign::PDTSequenceAssign(PDTCodeGraph & CG, PDTVar &target, PDTConstSequence &expression):
		PDTStatement(CG) {
	PDTNode* varNode = target.getNode();
	addChild(varNode);
	varNode->addParent(this);

	addChild(&expression);
	expression.addParent(this);
}

PDTVar * PDTSequenceAssign::getTarget() const {
	return dynamic_cast <PDTVar*>(children[0]);
}

PDTConstSequence * PDTSequenceAssign::getSequenceConst() const {
	return dynamic_cast<PDTConstSequence *>(children[1]);
}

